package mysql

import (
	"github.com/go-xorm/xorm"
	"github.com/pkg/errors"
	"github.com/pquerna/ffjson/ffjson"
)

// 跨服务请求 SQL 信息结构
type ActionSqlInfo struct {
	Table string        `json:"table"` // 操作数据表名称
	Func  string        `json:"func"`  // SQL 操作类型，Select、Delete、InsertOne、InsertList、Update
	Sql   string        `json:"sql"`   // 操作 SQL 语句
	Data  []byte        `json:"data"`  // 插入、修改 sql 对应的模型数据的 JSON 字节切片
	Value []interface{} `json:"value"` // 所有条件具体值
	Obj   interface{}   // 服务端根据表名称注入模型
	// Auraro 数据库写入转发模式
	// 参考：https://docs.aws.amazon.com/zh_cn/AmazonRDS/latest/AuroraUserGuide/aurora-global-database-write-forwarding.html#aurora-global-database-write-forwarding-compatibility
	AuroraReplicaReadConsistency string // 仅在服务运行模式为 test/release 的模式下生效，值范围：eventual、session、global
}

type SqlResponse struct {
	Has  bool   `json:"has"`  // 查询类 SQL 结果是否存在值
	Int  int64  `json:"int"`  // 查询或影响数量结果
	Data []byte `json:"data"` // 查询结果 JSON 字节切片
}

// 查询操作
func (h *Handler) Action(info *ActionSqlInfo) (res *SqlResponse, err error) {
	// 1. 获取数据库引擎
	var session *xorm.Session
	if h.EngineGroup != nil {
		session = h.EngineGroup.NewSession()
	} else if h.Engine != nil {
		session = h.Engine.NewSession()
	} else {
		return res, errors.New("xorm engine cannot be empty")
	}
	defer session.Close()
	// 2. 设置 aurora 的写入转发模式
	session, err = h.setAuroraReplicaReadConsistency(session, info.AuroraReplicaReadConsistency)
	if err != nil {
		return
	}
	// 3. 执行 SQL 语句
	res = &SqlResponse{}
	switch info.Func {
	case "Select":
		// 初始化值
		values := make([]interface{}, 0)
		values = append(values, info.Sql)
		values = append(values, info.Value...)
		// 执行查询操作
		list, err := session.QueryInterface(values...)
		if err != nil || len(list) == 0 {
			return res, err
		}
		// 设置结果有值
		res.Has = true
		// 遍历数据，将字符串字节转为字符串
		for _, v := range list {
			for k, info := range v {
				if i, ok := info.([]byte); ok {
					v[k] = string(i)
				} else {
					v[k] = info
				}
			}
		}
		// 查询结果转为 json 的字节切片
		res.Data, err = ffjson.Marshal(list)
		return res, nil
	case "Delete":
		// 初始化值
		values := make([]interface{}, 0)
		values = append(values, info.Sql)
		values = append(values, info.Value...)
		// 执行删除操作
		result, err := session.Exec(values...)
		if err != nil {
			return res, err
		}
		res.Int, err = result.RowsAffected()
		return res, err
	case "InsertOne":
		// 插入单条数据
		res.Int, err = session.Insert(info.Obj)
		return res, err
	case "InsertList":
		// 插入多条数据
		value, err := h.transactionWork([]*SqlInfo{{Func: "Insert", Obj: info.Obj}})
		if err != nil {
			return res, err
		}
		res.Int = value[0]
		return res, err
	case "Update":
		// 判断是否存在条件 sql
		if info.Sql == "" {
			return res, errors.New("update：sql where cannot be empty")
		}
		// 开启事务
		if err = session.Begin(); err != nil {
			return
		}
		// 执行 SQL
		res.Int, err = session.Where(info.Sql, info.Value...).Update(info.Obj)
		if err != nil {
			_ = session.Rollback()
			return res, err
		}
		// 判断影响行数
		if res.Int > 100 {
			_ = session.Rollback()
			return res, errors.New("update：the number of affected lines exceeds 100 lines")
		}
		// 提交事务
		err = session.Commit()
		return res, err
	default:
		return res, errors.New("sql func is invalid")
	}
}
